import axios from 'axios';
import type {
  AxiosInstance,
  AxiosRequestConfig,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios';
import { message } from 'antd';
import { AxiosCanceler } from './axiosCancel';
import { isFunction } from '@/utils/is';
import ErrorInterceptor from './error';

import type { CreateAxiosOptions, AxiosTransform } from './axiosTransform';

// 记录和显示错误
function logError(msg: string) {
  message.error(msg);
}

const transform: AxiosTransform = {
  requestInterceptors: config => {
    return config;
  },
  responseInterceptors: (res: AxiosResponse) => {
    if (res.data.errorCode === 200 || res.config.headers?.passInterceptors) {
      if (res.config.headers?.intact) {
        return res;
      }
      return res.data;
    } else {
      if (res.data instanceof ArrayBuffer || res.data instanceof Blob) {
        return res;
      }
      logError(res.data.errorMsg);
      if (res.data.errorCode === 401) {
        window.location.replace('#/login');
      }
      return Promise.reject(res.data);
    }
  },
  responseInterceptorsCatch: (axiosInstance: AxiosInstance, error: any) => {
    if (axios.isCancel(error)) {
      return new Promise(() => {});
    }
    try {
      logError(error.data.errorMsg);
    } catch {
      throw new Error(error as unknown as string);
    }
    return Promise.reject(error);
  },
};
class Request {
  private instance: AxiosInstance;
  private readonly config: CreateAxiosOptions;

  constructor(config: AxiosRequestConfig) {
    this.config = { ...config, transform };
    this.instance = axios.create(this.config);
    this.setupInterceptors();
    // 请求拦截
    this.instance.interceptors.request.use(
      (config: AxiosRequestConfig): InternalAxiosRequestConfig => {
        const Token = localStorage.getItem('satoken');
        if (Token) {
          const satoken = JSON.parse(Token);
          config = {
            ...config,
            headers: {
              ...config.headers,
              satoken: satoken.tokenInfo.tokenValue,
            },
          };
        }
        return config as InternalAxiosRequestConfig;
      },
      (err: any) => err
    );
    // 响应拦截
    // this.instance.interceptors.response.use(
    //   (res: AxiosResponse) => {
    //     if (
    //       res.data.errorCode === 200 ||
    //       res.config.headers?.passInterceptors
    //     ) {
    //       if (res.config.headers?.intact) {
    //         return res;
    //       }
    //       return res.data;
    //     } else {
    //       logError(res.data.errorMsg);
    //       return new Promise(() => {});
    //     }
    //   },
    //   (err: any) => err
    // );
  }

  private setupInterceptors() {
    const {
      // instance,
      config: { transform },
    } = this;
    if (!transform) {
      return;
    }
    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;

    const axiosCanceler = new AxiosCanceler();

    // 请求拦截
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 当有token时保留
        // const { requestOptions } = this.config;
        // const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true;
        // !ignoreCancelToken &&

        // 重复请求 add cancel pending
        axiosCanceler.addPending(config);

        if (requestInterceptors && isFunction(requestInterceptors)) {
          config = requestInterceptors(config, this.config);
        }
        return config;
      },
      undefined
    );

    // 请求异常处理
    requestInterceptorsCatch &&
      isFunction(requestInterceptorsCatch) &&
      this.instance.interceptors.request.use(
        undefined,
        requestInterceptorsCatch
      );

    // 响应拦截
    this.instance.interceptors.response.use((res: AxiosResponse<any>) => {
      res && axiosCanceler.removePending(res.config);
      if (responseInterceptors && isFunction(responseInterceptors)) {
        res = responseInterceptors(res);
      }
      return res;
    }, undefined);
    // 异常响应处理
    responseInterceptorsCatch &&
      isFunction(responseInterceptorsCatch) &&
      this.instance.interceptors.response.use(undefined, ErrorInterceptor);
  }

  get<T = any>(config: AxiosRequestConfig, params?: any): Promise<T> {
    return this.instance.get(config.url as string, params);
  }

  post<T = any>(config: AxiosRequestConfig, params?: any): Promise<T> {
    const { url, ...conf } = config;
    return this.instance.post(url as string, params, conf);
  }

  put<T = any>(config: AxiosRequestConfig, params?: any): Promise<T> {
    return this.instance.put(config.url as string, params);
  }

  delete<T = any>(config: AxiosRequestConfig, params?: any): Promise<T> {
    return this.instance.delete(config.url as string, params);
  }
}

const axiosConfig: AxiosRequestConfig = {
  baseURL: process.env.REACT_APP_BASE_URL,
  timeout: 0,
};
const request = new Request(axiosConfig);
export default request;
